from OCC.Core.gp import gp_Pnt, gp_Trsf, gp_OX, gp_Vec, gp_DZ, gp_Ax2
from OCC.Core.GC import GC_MakeArcOfCircle, GC_MakeSegment
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire, BRepBuilderAPI_Transform, \
    BRepBuilderAPI_MakeFace
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism, BRepPrimAPI_MakeCylinder
from OCC.Core.TopoDS import topods
from OCC.Display.SimpleGui import init_display
from OCC.Core.BRepFilletAPI import BRepFilletAPI_MakeFillet
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopAbs import TopAbs_EDGE, TopAbs_FACE
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Core.TopTools import TopTools_ListOfShape
from OCC.Core.BRep import BRep_Tool_Surface
from OCC.Core.Geom import Geom_Plane
from OCC.Core.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid


def geom_plane_from_face(aface):
    return Geom_Plane.DownCast(BRep_Tool_Surface(aface))


def face_is_plane(face):
    hs = BRep_Tool_Surface(face)
    downcast_result = Geom_Plane.DownCast(hs)
    # return not (downcast_result is None)
    return downcast_result is not None


display, start_display, add_menu, add_function_to_menu = init_display()

width = 50
height = 70
thickness = 30

# 瓶身

aPnt1 = gp_Pnt(-width / 2, 0, 0)
aPnt2 = gp_Pnt(-width / 2, -thickness / 4, 0)
aPnt3 = gp_Pnt(0, -thickness / 2, 0)
aPnt4 = gp_Pnt(width / 2, -thickness / 4, 0)
aPnt5 = gp_Pnt(width / 2, 0, 0)

display.DisplayShape(aPnt1)
display.DisplayShape(aPnt2)
display.DisplayShape(aPnt3)
display.DisplayShape(aPnt4)
display.DisplayShape(aPnt5)

aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4)
aSegment1 = GC_MakeSegment(aPnt1, aPnt2)
aSegment2 = GC_MakeSegment(aPnt4, aPnt5)

aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value())
aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value())
aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value())
aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge())

xAxis = gp_OX()
aTrsf = gp_Trsf()
aTrsf.SetMirror(xAxis)
aBrespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf)
aMirroredShape = aBrespTrsf.Shape()
aMirroredWire = topods.Wire(aMirroredShape)

mkWire = BRepBuilderAPI_MakeWire()
mkWire.Add(aWire.Wire())
mkWire.Add(aMirroredWire)
myWireProfile = mkWire.Wire()

myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile)
aPrismVec = gp_Vec(0, 0, height)
myBody = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec)

mkFillet = BRepFilletAPI_MakeFillet(myBody.Shape())
anEdgeExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_EDGE)

while anEdgeExplorer.More():
    anEdge = topods.Edge(anEdgeExplorer.Current())
    mkFillet.Add(thickness / 12, anEdge)
    anEdgeExplorer.Next()

# 瓶颈
neckLocation = gp_Pnt(0, 0, height)
neckAxis = gp_DZ()
neckAx2 = gp_Ax2(neckLocation, neckAxis)

neckRadius = thickness / 4
neckHeight = height / 10
MKCylinder = BRepPrimAPI_MakeCylinder(neckAx2, neckRadius, neckHeight)
myBody = BRepAlgoAPI_Fuse(mkFillet.Shape(), MKCylinder.Shape())

# 挖空
faceToRemove = None
zMax = -1

aFaceExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_FACE)
while aFaceExplorer.More():
    aFace = topods.Face(aFaceExplorer.Current())
    if face_is_plane(aFace):
        aPlane = geom_plane_from_face(aFace)
        aPnt = aPlane.Location()
        aZ = aPnt.Z()
        if aZ > zMax:
            zMax = aZ
            faceToRemove = aFace
    aFaceExplorer.Next()

facesToRemove = TopTools_ListOfShape()
facesToRemove.Append(faceToRemove)

myBody = BRepOffsetAPI_MakeThickSolid(myBody.Shape(), facesToRemove, -thickness / 50, 0.001)

# display.DisplayShape(myWireProfile)
display.DisplayShape(myBody.Shape())

start_display()
